/* 
 * 
 * Copyright 2011 The University of Adelaide
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License. 
 *  
 */

package au.org.aekos.ands.alis.process;

import static au.org.aekos.ands.global.Util.earliest;
import static au.org.aekos.ands.global.Util.latest;
import static au.org.aekos.ands.global.Util.pluralise;

import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import au.org.aekos.ands.alis.data.SiteLocation;
import au.org.aekos.ands.alis.data.SiteSurvey;
import au.org.aekos.ands.alis.data.Visit;
import au.org.aekos.ands.alis.web.ALIS;
import au.org.aekos.ands.global.Schema;
import au.org.aekos.ands.global.Schema.Attribute;
import au.org.ands.standards.rifCs.registryObjects.CollectionDocument.Collection;
import au.org.ands.standards.rifCs.registryObjects.CoverageType;
import au.org.ands.standards.rifCs.registryObjects.RegistryObjectsDocument.RegistryObjects.RegistryObject;

/**
 * The collection generator for ALIS.
 * Interfaces with data access objects that fetch information from the
 * ALIS database.
 */
public class GenerateCollection {
	private static final String DEFAULT_PROJECTION = "GDA94";
	
	private Schema schema;
	
	/**
	 * Instantiates a new collection generator.
	 *
	 * @param schema the schema through which the collection is defined.
	 */
	public GenerateCollection(Schema schema) { this.schema = schema; }

    /**
     * Generates the collection for the given visit type.
     * Metadata includes spatial and temporal coverage and information
     * on site surveys and visits.
     *
     * @param visitType the visit type.
     * @param visits the visits.
     * @return a new registry object containing the collection.
     */
    public RegistryObject generateCollection(String visitType, List<Visit> visits) {
    	if ((visitType == null) || (visits == null)) { return null; }
    	
		RegistryObject object = schema.generateCollection(visitType);
    	Collection collection = object.getCollection();
		
		// Related Objects
		
		collection.addNewRelatedObject().set(schema.linkToActivity(ALIS.ACTIVITY));
				
		// Coverage (temporal and spatial)
		
		CoverageType coverage = collection.addNewCoverage();
		
		Date minDate = null, maxDate = null;
		SortedSet<Double> latitudes = new TreeSet<Double>();
		SortedSet<Double> longitudes = new TreeSet<Double>();
		
		int siteSurveyCount = 0;
		
		// For each visit, examine each site survey.
		// For each site survey, fetch spatial and temporal metadata.
		
		for (Visit visit : visits) {
			Set<SiteSurvey> surveys = visit.getSiteSurveys();
			siteSurveyCount += surveys.size();

			for (SiteSurvey survey : surveys) {					
				// Grab the dates.
				
				Date startDate = survey.getSurveyDate();
				minDate = earliest(minDate, startDate);

				Date endDate = survey.getFinalisedDate();
				maxDate = latest(maxDate, endDate);

				// Grab the locations.
				
				int siteID = survey.getSiteNumber().getSiteNumber();
				SiteLocation siteLocation = SiteLocation.findSiteLocation(siteID);
				Double longitude = siteLocation.getPointX();
				Double latitude = siteLocation.getPointY();
				if ((longitude != null) && (latitude != null)) {
					latitudes.add(latitude);
					longitudes.add(longitude);
				}
			}			
		}

		// Do we have spatial coverage?
		
		if ((!latitudes.isEmpty()) && (!longitudes.isEmpty())) {
        	double s = latitudes.first();
        	double n = latitudes.last();
        	double w = longitudes.first();
        	double e = longitudes.last();
        	
        	coverage.addNewSpatial().set(Schema.generateSpatialCoverage(n, e, s, w, DEFAULT_PROJECTION));
		}

		// Do we have temporal coverage?
		
		if ((minDate != null) || (maxDate != null)) {
			coverage.addNewTemporal().set(Schema.generateTemporalCoverage(minDate, maxDate));
		}
		
		// Notes
		
		String visitString = pluralise(visits.size(), "visit", false);
		String siteSurveyString = pluralise(siteSurveyCount, "site survey", false);
		String noteString = "Collection includes " + visitString + " with " + siteSurveyString + ".";
		collection.addNewDescription().set(Schema.generateDescription(Attribute.NOTES, noteString));
		
		return object;
    }    
}
